﻿namespace Mercury.ParticleEngine.EmitterVisualizer
{
    using System;
    using System.Timers;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    using Mercury.ParticleEngine.EmitterShapes;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private Boolean _simulating;

        private VisualizerParticleEmitter _particleEmitter;

        private Rectangle[,] _rectangles;

        private Timer _timer;

        private Single _totalTime;

        public MainWindow()
        {
            InitializeComponent();

            this.Restart(256);

            EmitterCapacitySelection.SelectionChanged += EmitterCapacitySelection_SelectionChanged;
        }

        private void EmitterCapacitySelection_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var item = (ComboBoxItem)e.AddedItems[0];

            this.Restart(Convert.ToInt32(item.Content));
        }

        private void Restart(Int32 capacity)
        {
            if (_simulating)
                StopSimulation();

            SetupGrid(capacity);

            this._particleEmitter = new VisualizerParticleEmitter(capacity, TimeSpan.FromSeconds(8), new PointShape(), new VisualizerStateManager(capacity, _rectangles))
            {
                ReleaseQuantity = 1
            };

            _timer = new Timer
            {
                AutoReset = true,
                Interval = 20,
                Enabled = true
            };

            _timer.Elapsed += Tick;

            _timer.Start();

            _simulating = true;
        }

        private void StopSimulation()
        {
            _timer.Elapsed -= Tick;
            _timer.Dispose();

            _totalTime = 0f;

            _simulating = false;
        }

        private void SetupGrid(Int32 capacity)
        {
            ParticleGrid.Children.Clear();
            
            ParticleGrid.ColumnDefinitions.Clear();
            ParticleGrid.RowDefinitions.Clear();

            for (int i = 0; i < Math.Sqrt(capacity); i++)
            {
                ParticleGrid.ColumnDefinitions.Add(new ColumnDefinition());
                ParticleGrid.RowDefinitions.Add(new RowDefinition());
            }

            var widthHeight = Convert.ToInt32(Math.Sqrt(capacity));

            _rectangles = new Rectangle[widthHeight, widthHeight];

            for (int i = 0; i < capacity; i++)
            {
                var rect = _rectangles[i / widthHeight, i % widthHeight] = new Rectangle
                {
                    Margin = new Thickness(0.5d),
                };

                rect.Fill = Brushes.Gray;

                rect.SetValue(Grid.RowProperty, i % widthHeight);
                rect.SetValue(Grid.ColumnProperty, i / widthHeight);

                ParticleGrid.Children.Add(rect);
            }
        }

        private void Tick(Object sender, ElapsedEventArgs e)
        {
            _totalTime += 0.1f;

            if (_triggering)
            {
                var triggerContext = new TriggerContext(_totalTime, Coordinate.Origin);

                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => this._particleEmitter.Trigger(ref triggerContext)));
            }

            var updateContext = new UpdateContext(_totalTime, 1000f / (float)_timer.Interval);

            this._particleEmitter.Update(ref updateContext);

            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(EchoStatus));
        }

        private void EchoStatus()
        {
            foreach (var rect in _rectangles)
            {
                rect.Fill = Brushes.Gray;
            }

            this._particleEmitter.Render();

            HeadLabel.Content = String.Format("Head: {0}", this._particleEmitter.Head);
            NextLabel.Content = String.Format("Next: {0}", this._particleEmitter.Next);
            CountLabel.Content = String.Format("Count: {0}", this._particleEmitter.ActiveParticlesCount);
        }

        private Boolean _triggering;

        private void Trigger_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _triggering = true;
        }

        private void Trigger_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _triggering = false;
        }
    }
}
